54장. CloudFront → API Gateway → ALB 의 역할 분담
이 장에서 말하고자 하는 것
지금까지 우리는 외부 트래픽의 세 계층을 모두 만났다.
- CloudFront — 엣지, CDN, DDoS, TLS 종료
- API Gateway — 인증, Rate limit, 변환
- ALB — 서비스 라우팅, 헬스 체크, 트래픽 분배
이 셋이 한 줄에 늘어선다.
그럼 왜 셋 다 필요한가? 무엇을 누가 책임지나?
1. 각 계층이 잘하는 칸이 다르다
| 책임 | CloudFront | API Gateway | ALB |
|---|---|---|---|
| 정적 콘텐츠 캐시 | ✅ | ❌ | ❌ |
| DDoS / WAF 흡수 | ✅ (Shield) | △ | △ |
| TLS 종료 (외부) | ✅ | △ | △ |
| Rate limit | △ | ✅ | △ |
| JWT 인증 | ❌ | ✅ | △ |
| 경로 기반 서비스 분배 | △ | △ | ✅ |
| 헬스 체크 + 자가 치유 | ❌ | ❌ | ✅ |
| 컨테이너 IP 자동 등록 | ❌ | ❌ | ✅ |
2. 흐름 한 번 더
[사용자]
↓ HTTPS, DNS
[CloudFront] ← 캐시, DDoS, 엣지 TLS
↓
[API Gateway] ← 인증, Rate limit, 변환
↓ VPC Link
[Private ALB] ← 경로 라우팅, 헬스 체크
↓
[ECS Service] ← 자가 치유, 스케일링
↓
[Container] ← 비즈니스 로직
각 단계가 자기 영역에서만 일한다.
3. 책임 분리의 효과
1. 한 계층이 죽어도 다른 게 일부 흡수
- CloudFront 캐시가 origin 다운을 일정 시간 가린다
- API Gateway가 Rate limit으로 폭증을 흡수해 ALB가 안 죽는다
- ALB 헬스 체크가 죽은 Task를 즉시 분리
2. 보안 깊이 (Defense in Depth)
- CloudFront WAF — 1차 그물
- API Gateway 인증 — 2차 검증
- VPC Link · 보안 그룹 — 3차 격리
3. 비용 최적화
- 정적 응답은 CloudFront에서 흡수
- 미인증 요청은 API Gateway에서 차단
4. 흔히 묻는 결정들
Q. 작은 서비스도 셋 다 깔아야 하나?
- MVP / 내부 도구 → ALB 만으로 충분
- 공개 API · SaaS → CloudFront + API Gateway + ALB
- 정적 페이지 + 약간의 API → CloudFront + API Gateway (Lambda 가능)
Q. CloudFront 없이 API Gateway 만 두면?
- DDoS 흡수 약함
- TLS 종료가 사용자에서 멀다
- 정적 자원 캐시 없음
Q. API Gateway 없이 CloudFront → ALB 만 두면?
- 인증을 애플리케이션이 다 한다
- Rate limit이 빈약
- 토큰 검증이 ECS까지 도달 — 부하
5. 한 도메인에서 정적과 동적 동시에
example.com
├─ /static/* → S3
├─ /api/* → API Gateway → ALB → ECS
└─ /* → S3 (SPA index.html)
CloudFront 한 배포 안에서 두 origin을 가진다.
- CORS 문제 없음
- 사용자가 보기에 한 도메인
6. 우리 서비스의 완성형
[Route 53] api.example.com
↓ ALIAS
[CloudFront] (us-east-1 ACM, WAF)
├─ /static/* → S3 (OAC)
└─ /api/* → APIGW
↓ JWT Authorizer
↓ VPC Link
[Private ALB] (서울 ACM)
├─ /api/orders/* → ECS "orders"
├─ /api/users/* → ECS "users"
└─ /api/payments/* → ECS "payments"
↓
[ECS Service · Task · Container]
↓
[RDS · DynamoDB · ElastiCache]
이 그림이 1~54장의 결과물이다.
7. 직접 확인해보기 — 흐름 디버깅
문제가 어디서 났는지 모를 때
# 1. CloudFront 응답 헤더
curl -I https://api.example.com/api/orders
# → x-cache, x-amz-cf-id 확인
# 2. API Gateway 도달 여부
aws logs tail /aws/apigw/main --follow
# 3. ALB 액세스 로그
aws s3 cp s3://alb-logs/... - | head
# 4. ECS Task 로그
aws logs tail /ecs/orders --follow
“어느 계층까지 도달했나” 가 디버깅의 시작이다
8. 코드로는 이렇게 생겼다 — Terraform (origin 부분만)
# CloudFront: ALB가 아니라 API Gateway를 origin으로
origin {
domain_name = replace(aws_apigatewayv2_api.main.api_endpoint, "https://", "")
origin_id = "apigw"
custom_origin_config {
origin_protocol_policy = "https-only"
http_port = 80
https_port = 443
origin_ssl_protocols = ["TLSv1.2"]
}
}
그 아래는 38·52장 코드 그대로.
9. 이렇게 쓰면 망한다 — 안티패턴
안티패턴 1. ALB가 인터넷에 노출돼 있다
우회로가 열려서 보안 효과가 의미를 잃는다.
진짜 origin은 무조건 비공개
안티패턴 2. 모든 계층에서 인증을 또 한다
운영이 못 따라간다.
인증은 API Gateway 한 곳에서, 그 뒤로는 신뢰
안티패턴 3. 같은 도메인을 두 계층에서 동시에 다룬다
DNS 매핑이 꼬인다.
한 도메인 → 한 진입점 (CloudFront)
안티패턴 4. 각 계층의 로그를 안 모은다
장애 추적이 안 된다.
10. 한 줄로 정리
CloudFront는 엣지에서, API Gateway는 인증/제한에서, ALB는 서비스 분배에서
각자 잘하는 일만 한다 — 그래서 셋을 함께 둔다
11. 이 장의 핵심 정리
- CloudFront · API Gateway · ALB는 책임이 겹치지 않는 세 계층이다.
- 보안 깊이와 비용 최적화가 동시에 이뤄진다.
- 작은 서비스는 ALB만으로 시작 가능, 공개 SaaS는 셋 다.
- ALB는 반드시 비공개.
- 인증은 API Gateway 한 곳에서.
- 각 계층의 로그를 모두 켜야 장애 추적이 가능하다.